package org.yelongframework.pdm.xml;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.yelongframework.util.Assert;
import org.yelongframework.xml.XmlDocument;
import org.yelongframework.xml.XmlElement;
import org.yelongframework.xml.XmlNode;
import org.yelongframework.xml.XmlNodeList;
import org.yelongframework.xml.resolver.XmlResolveException;
import org.yelongframework.xml.resolver.XmlResolver;
import org.yelongframework.xml.utils.XmlNodeListUtils;

/**
 * 默认实现
 * 
 * @since 1.0.0
 */
public class DefaultXmlPdmResolver extends AbstractXmlPdmResolver {

	private final XmlResolver xmlResolver;

	// ==================================================constructor==================================================

	public DefaultXmlPdmResolver(XmlResolver xmlResolver) {
		Assert.notNull(xmlResolver, "xmlResolver cannot be null");
		this.xmlResolver = xmlResolver;
	}

	// ==================================================解析表==================================================

	@Override
	public List<CTables> resolveCTables(InputStream inputStream) throws XmlResolveException, IOException {
		XmlDocument xmlDocument = xmlResolver.resolve(inputStream);
		XmlNodeList<XmlElement> cTablesNodeList = xmlDocument.getElementsByTagName("c:Tables");
		if (XmlNodeListUtils.isEmpty(cTablesNodeList)) {
			return Collections.emptyList();
		}
		List<CTables> cTablesList = new ArrayList<>();
		for (XmlElement cTablesXmlElement : cTablesNodeList.getList()) {
			cTablesList.add(resolveCTables(cTablesXmlElement));
		}
		return cTablesList;
	}

	// ==================================================表==================================================

	/**
	 * 解析c:Tables
	 * 
	 * @param cTablesXmlElement 元素
	 * @return 对象
	 */
	protected CTables resolveCTables(XmlElement cTablesXmlElement) {
		CTables cTables = new CTables();
		XmlNodeList<XmlElement> oTableNotList = cTablesXmlElement.getElementsByTagName("o:Table");
		if (XmlNodeListUtils.isEmpty(oTableNotList)) {
			return cTables;
		}
		for (XmlElement oTableXmlElement : oTableNotList.getList()) {
			cTables.addOTable(resolveOTable(oTableXmlElement));
		}
		return cTables;
	}

	/**
	 * o:Table
	 * 
	 * @param oTableXmlElement 元素
	 * @return 对象
	 */
	protected OTable resolveOTable(XmlElement oTableXmlElement) {
		OTable oTable = new OTable();
		oTable.setId(oTableXmlElement.getAttribute("Id"));
		XmlNodeList<XmlNode> oTableChildNodes = oTableXmlElement.getChildNodes();
		oTable.setaObjectId(oTableChildNodes.getFirstTextContentByNodeName("a:ObjectID"));
		oTable.setaName(oTableChildNodes.getFirstTextContentByNodeName("a:Name"));
		oTable.setaCode(oTableChildNodes.getFirstTextContentByNodeName("a:Code"));
		oTable.setaCreationDate(oTableChildNodes.getFirstTextContentByNodeName("a:CreationDate"));
		oTable.setaCreator(oTableChildNodes.getFirstTextContentByNodeName("a:Creator"));
		oTable.setaModificationDate(oTableChildNodes.getFirstTextContentByNodeName("a:ModificationDate"));
		oTable.setaModifier(oTableChildNodes.getFirstTextContentByNodeName("a:Modifier"));
		oTable.setaComment(oTableChildNodes.getFirstTextContentByNodeName("a:Comment"));
		oTable.setcColumns(resolveCColumns(oTableChildNodes.getFirstElementByNodeName("c:Columns")));
		oTable.setcKeys(resolveCKeys(oTableChildNodes.getFirstElementByNodeName("c:Keys")));
		oTable.setcPrimaryKey(resolveCPrimaryKey(oTableChildNodes.getFirstElementByNodeName("c:PrimaryKey")));
		return oTable;
	}

	// ==================================================列==================================================

	/**
	 * c:Columns
	 * 
	 * @param cColumnsXmlElement 元素
	 * @return 对象
	 */
	protected CColumns resolveCColumns(XmlElement cColumnsXmlElement) {
		if (null == cColumnsXmlElement) {
			return null;
		}
		CColumns cColumns = new CColumns();
		XmlNodeList<XmlElement> oColumnNodeList = cColumnsXmlElement.getElementsByTagName("o:Column");
		if (XmlNodeListUtils.isEmpty(oColumnNodeList)) {
			return cColumns;
		}
		for (XmlElement oColumn : oColumnNodeList.getList()) {
			cColumns.addOColumn(resolveOColumn(oColumn));
		}
		return cColumns;
	}

	/**
	 * o:Column
	 * 
	 * @param oColumnXmlElement 元素
	 * @return 对象
	 */
	protected OColumn resolveOColumn(XmlElement oColumnXmlElement) {
		OColumn oColumn = new OColumn();
		oColumn.setId(oColumnXmlElement.getAttribute("Id"));
		XmlNodeList<XmlNode> oColumnChildNodes = oColumnXmlElement.getChildNodes();
		oColumn.setaObjectId(oColumnChildNodes.getFirstTextContentByNodeName("a:ObjectID"));
		oColumn.setaName(oColumnChildNodes.getFirstTextContentByNodeName("a:Name"));
		oColumn.setaCode(oColumnChildNodes.getFirstTextContentByNodeName("a:Code"));
		oColumn.setaCreationDate(oColumnChildNodes.getFirstTextContentByNodeName("a:CreationDate"));
		oColumn.setaCreator(oColumnChildNodes.getFirstTextContentByNodeName("a:Creator"));
		oColumn.setaModificationDate(oColumnChildNodes.getFirstTextContentByNodeName("a:ModificationDate"));
		oColumn.setaModifier(oColumnChildNodes.getFirstTextContentByNodeName("a:Modifier"));
		oColumn.setaComment(oColumnChildNodes.getFirstTextContentByNodeName("a:Comment"));
		oColumn.setaDataType(oColumnChildNodes.getFirstTextContentByNodeName("a:DataType"));
		oColumn.setaLength(oColumnChildNodes.getFirstTextContentByNodeName("a:Length"));

		String aColumnMandatory = oColumnChildNodes.getFirstTextContentByNodeName("a:Column.Mandatory");
		if (StringUtils.isBlank(aColumnMandatory)) {
			aColumnMandatory = oColumnChildNodes.getFirstTextContentByNodeName("a:Mandatory");
		}
		oColumn.setaColumnMandatory(aColumnMandatory);
		return oColumn;
	}

	// ==================================================键==================================================

	/**
	 * c:Keys
	 * 
	 * @param cColumnsXmlElement 元素
	 * @return 对象
	 */
	protected CKeys resolveCKeys(XmlElement cKeysXmlElement) {
		if (null == cKeysXmlElement) {
			return null;
		}
		CKeys cKeys = new CKeys();
		XmlNodeList<XmlElement> oKeyNodeList = cKeysXmlElement.getElementsByTagName("o:Key");
		if (XmlNodeListUtils.isEmpty(oKeyNodeList)) {
			return cKeys;
		}
		for (XmlElement oKey : oKeyNodeList.getList()) {
			cKeys.addOKey(resolveOKey(oKey));
		}
		return cKeys;
	}

	/**
	 * o:Column
	 * 
	 * @param oColumnXmlElement 元素
	 * @return 对象
	 */
	protected OKey resolveOKey(XmlElement oKeyXmlElement) {
		OKey oKey = new OKey();
		oKey.setId(oKeyXmlElement.getAttribute("Id"));
		XmlNodeList<XmlNode> oKeyChildNodes = oKeyXmlElement.getChildNodes();
		oKey.setaObjectId(oKeyChildNodes.getFirstTextContentByNodeName("a:ObjectID"));
		oKey.setaName(oKeyChildNodes.getFirstTextContentByNodeName("a:Name"));
		oKey.setaCreationDate(oKeyChildNodes.getFirstTextContentByNodeName("a:CreationDate"));
		oKey.setaCreator(oKeyChildNodes.getFirstTextContentByNodeName("a:Creator"));
		oKey.setaModificationDate(oKeyChildNodes.getFirstTextContentByNodeName("a:ModificationDate"));
		oKey.setaModifier(oKeyChildNodes.getFirstTextContentByNodeName("a:Modifier"));
		oKey.setaName(oKeyChildNodes.getFirstTextContentByNodeName("a:Name"));
		oKey.setaCode(oKeyChildNodes.getFirstTextContentByNodeName("a:Code"));
		oKey.setcKeyColumns(resolveCKeyColumns(oKeyChildNodes.getFirstElementByNodeName("c:Key.Columns")));
		return oKey;
	}

	protected CKeyColumns resolveCKeyColumns(XmlElement cKeyColumnsXmlElement) {
		if (null == cKeyColumnsXmlElement) {
			return null;
		}
		CKeyColumns cKeyColumns = new CKeyColumns();
		XmlNodeList<XmlElement> oColumnNodeList = cKeyColumnsXmlElement.getElementsByTagName("o:Column");
		if (XmlNodeListUtils.isEmpty(oColumnNodeList)) {
			return cKeyColumns;
		}
		for (XmlElement oColumnXmlElement : oColumnNodeList.getList()) {
			cKeyColumns.addOColumnRef(oColumnXmlElement.getAttribute("Ref"));
		}
		return cKeyColumns;
	}

	// ==================================================主键==================================================

	protected CPrimaryKey resolveCPrimaryKey(XmlElement cPrimaryKeyXmlElement) {
		if (null == cPrimaryKeyXmlElement) {
			return null;
		}
		CPrimaryKey cPrimaryKey = new CPrimaryKey();
		XmlNodeList<XmlElement> oKeyNodeList = cPrimaryKeyXmlElement.getElementsByTagName("o:Key");
		if (XmlNodeListUtils.isEmpty(oKeyNodeList)) {
			return cPrimaryKey;
		}
		for (XmlElement oKeyXmlElement : oKeyNodeList.getList()) {
			cPrimaryKey.addOKeyRef(oKeyXmlElement.getAttribute("Ref"));
		}
		return cPrimaryKey;
	}

}
